home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
MPW_TOOL
/
TOOLS
/
TOOLS_WI
/
ICON_8
/
ICONT_FO
/
LCODE.C
< prev
next >
Wrap
Text File
|
1990-03-02
|
30KB
|
1,191 lines
/*
* lcode.c -- linker routines to parse .u1 files and produce icode.
*/
#include <math.h>
#include "::h:config.h"
#include "tproto.h"
#include "globals.h"
#include "opcode.h"
#include "link.h"
#include "general.h"
#include "::h:keyword.h"
#include "::h:version.h"
#include "::h:header.h"
/*
* Prototypes.
*/
hidden novalue backpatch Params((int lab));
hidden novalue clearlab Params((noargs));
hidden novalue flushcode Params((noargs));
hidden novalue intout Params((int oint));
hidden novalue lemit Params((int op,char *name));
hidden novalue lemitcon Params((int k));
hidden novalue lemiteven Params((noargs));
hidden novalue lemitin Params((int op,word offset,int n,char *name));
hidden novalue lemitint Params((int op,long i,char *name));
hidden novalue lemitl Params((int op,int lab,char *name));
hidden novalue lemitn Params((int op,word n,char *name));
hidden novalue lemitproc
Params((char *name,int nargs,int ndyn,int nstat, int fstat));
hidden novalue lemitr Params((int op,word loc,char *name));
hidden novalue outblock Params((char *addr,int count));
hidden novalue wordout Params((word oword));
#ifdef DeBugLinker
hidden novalue dumpblock Params((char *addr,int count));
#endif /* DeBugLinker */
#if AMIGA
#include <fcntl.h>
#endif /* AMIGA */
#ifndef MaxHeader
#define MaxHeader MaxHdr
#endif /* MaxHeader */
word pc = 0; /* simulated program counter */
#define outword(n) wordout((word)(n))
#define outop(n) intout((int)(n))
#define CodeCheck(n) if ((long)codep + n > (long)((long)codeb + maxcode))\
quit("out of code buffer space")
/*
* gencode - read .u1 file, resolve variable references, and generate icode.
* Basic process is to read each line in the file and take some action
* as dictated by the opcode. This action sometimes involves parsing
* of arguments and usually culminates in the call of the appropriate
* lemit* routine.
*/
novalue gencode()
{
register int op, k, lab;
int j, nargs, flags, implicit;
char *id, *name, *procname;
struct centry *cp;
struct gentry *gp;
struct fentry *fp;
union xval gg;
while ((op = getopc(&name)) != EOF) {
switch (op) {
/* Ternary operators. */
case Op_Toby:
case Op_Sect:
/* Binary operators. */
case Op_Asgn:
case Op_Cat:
case Op_Diff:
case Op_Div:
case Op_Eqv:
case Op_Inter:
case Op_Lconcat:
case Op_Lexeq:
case Op_Lexge:
case Op_Lexgt:
case Op_Lexle:
case Op_Lexlt:
case Op_Lexne:
case Op_Minus:
case Op_Mod:
case Op_Mult:
case Op_Neqv:
case Op_Numeq:
case Op_Numge:
case Op_Numgt:
case Op_Numle:
case Op_Numlt:
case Op_Numne:
case Op_Plus:
case Op_Power:
case Op_Rasgn:
case Op_Rswap:
case Op_Subsc:
case Op_Swap:
case Op_Unions:
/* Unary operators. */
case Op_Bang:
case Op_Compl:
case Op_Neg:
case Op_Nonnull:
case Op_Null:
case Op_Number:
case Op_Random:
case Op_Refresh:
case Op_Size:
case Op_Tabmat:
case Op_Value:
/* Instructions. */
case Op_Bscan:
case Op_Ccase:
case Op_Coact:
case Op_Cofail:
case Op_Coret:
case Op_Dup:
case Op_Efail:
case Op_Eret:
case Op_Escan:
case Op_Esusp:
case Op_Limit:
case Op_Lsusp:
case Op_Pfail:
case Op_Pnull:
case Op_Pop:
case Op_Pret:
case Op_Psusp:
case Op_Push1:
case Op_Pushn1:
case Op_Sdup:
newline();
lemit(op, name);
break;
case Op_Chfail:
case Op_Create:
case Op_Goto:
case Op_Init:
lab = getlab();
newline();
lemitl(op, lab, name);
break;
case Op_Cset:
case Op_Real:
k = getdec();
newline();
lemitr(op, lctable[k].c_pc, name);
break;
case Op_Field:
id = getid();
newline();
fp = flocate(id);
if (fp == NULL) {
lfatal(id, "invalid field name");
break;
}
lemitn(op, (word)(fp->f_fid-1), name);
break;
case Op_Int: {
long i;
k = getdec();
newline();
cp = &lctable[k];
/*
* Check to see if a large integers has been converted to a string.
* If so, generate the code for +s.
*/
if (cp->c_flag & F_StrLit) {
id = cp->c_val.sval;
lemit(Op_Pnull,"pnull");
lemitin(Op_Str, (word)(id-lsspace), cp->c_length, "str");
lemit(Op_Number,"number");
break;
}
i = (long)cp->c_val.ival;
lemitint(op, i, name);
break;
}
case Op_Invoke:
k = getdec();
newline();
if (k == -1)
lemit(Op_Apply,"apply");
else
lemitn(op, (word)k, name);
break;
case Op_Keywd:
k = getdec();
newline();
switch (k) {
case K_FAIL:
lemit(Op_Efail,"efail");
break;
case K_NULL:
lemit(Op_Pnull,"pnull");
break;
default:
lemitn(op, (word)k, name);
}
break;
case Op_Llist:
k = getdec();
newline();
lemitn(op, (word)k, name);
break;
case Op_Lab:
lab = getlab();
newline();
#ifdef DeBugLinker
if (Dflag)
fprintf(dbgfile, "L%d:\n", lab);
#endif /* DeBugLinker */
backpatch(lab);
break;
case Op_Line:
if (lnfree >= &lntable[nsize])
quit("out of line number table space");
lnfree->ipc = pc;
lineno = getdec();
lnfree->line = lineno;
lnfree++;
#ifdef EvalTrace
lemitn(op, (word)lineno, name);
#endif /* EvalTrace */
newline();
#ifdef LineCodes
lemit(Op_Noop,"noop");
#endif /* LineCodes */
break;
#ifdef EvalTrace
case Op_Colm:
colmno = getdec();
lemitn(op, (word)colmno, name);
break;
#endif /* EvalTrace */
case Op_Mark:
lab = getlab();
newline();
lemitl(op, lab, name);
break;
case Op_Mark0:
lemit(op, name);
break;
case Op_Str:
k = getdec();
newline();
cp = &lctable[k];
id = cp->c_val.sval;
lemitin(op, (word)(id-lsspace), cp->c_length, name);
break;
case Op_Tally:
k = getdec();
newline();
lemitn(op, (word)k, name);
break;
case Op_Unmark:
lemit(Op_Unmark, name);
break;
case Op_Var:
k = getdec();
newline();
flags = lltable[k].l_flag;
if (flags & F_Global)
lemitn(Op_Global, (word)(lltable[k].l_val.global-lgtable),
"global");
else if (flags & F_Static)
lemitn(Op_Static, (word)(lltable[k].l_val.staticid-1), "static");
else if (flags & F_Argument)
lemitn(Op_Arg, (word)(lltable[k].l_val.offset-1), "arg");
else
lemitn(Op_Local, (word)(lltable[k].l_val.offset-1), "local");
break;
/* Declarations. */
case Op_Proc:
procname = getid();
newline();
locinit();
clearlab();
lineno = 0;
gp = glocate(procname);
implicit = gp->g_flag & F_ImpError;
nargs = gp->g_nargs;
lemiteven();
break;
case Op_Local:
k = getdec();
flags = getoct();
id = getid();
putlocal(k, id, flags, implicit, procname);
break;
case Op_Con:
k = getdec();
flags = getoct();
if (flags & F_IntLit) {
{
long m;
char *s;
j = getdec(); /* number of characters in integer */
m = getint(j,&s); /* convert if possible */
if (m < 0) { /* negative indicates integer too big */
gg.sval = s; /* convert to a string */
putconst(k, F_StrLit, j, pc, &gg);
}
else { /* integers is small enough */
gg.ival = m;
putconst(k, flags, 0, pc, &gg);
}
}
}
else if (flags & F_RealLit) {
gg.rval = getreal();
putconst(k, flags, 0, pc, &gg);
}
else if (flags & F_StrLit) {
j = getdec();
gg.sval = getstrlit(j);
putconst(k, flags, j, pc, &gg);
}
else if (flags & F_CsetLit) {
j = getdec();
gg.sval = getstrlit(j);
putconst(k, flags, j, pc, &gg);
}
else
fprintf(stderr, "gencode: illegal constant\n");
newline();
lemitcon(k);
break;
case Op_Filen:
if (fnmfree >= &fnmtbl[fnmsize])
quit("out of file name table space");
fnmfree->ipc = pc;
fnmfree->fname = getrest() - lsspace;
/* fnmfree->fname = getid() - lsspace; */
fnmfree++;
newline();
break;
case Op_Declend:
newline();
gp->g_pc = pc;
lemitproc(procname, nargs, dynoff, lstatics-static1, static1);
break;
case Op_End:
newline();
flushcode();
break;
default:
fprintf(stderr, "gencode: illegal opcode(%d): %s\n", op, name);
newline();
}
}
}
/*
* lemit - emit opcode.
* lemitl - emit opcode with reference to program label.
* for a description of the chaining and backpatching for labels.
* lemitn - emit opcode with integer argument.
* lemitr - emit opcode with pc-relative reference.
* lemitin - emit opcode with reference to identifier table & integer argument.
* lemitint - emit word opcode with integer argument.
* lemiteven - emit null bytes to bring pc to word boundary.
* lemitcon - emit constant table entry.
* lemitproc - emit procedure block.
*
* The lemit* routines call out* routines to effect the "outputting" of icode.
* Note that the majority of the code for the lemit* routines is for debugging
* purposes.
*/
static novalue lemit(op, name)
int op;
char *name;
{
#ifdef DeBugLinker
if (Dflag)
fprintf(dbgfile, "%ld:\t%d\t\t\t\t# %s\n", (long)pc, op, name);
#else /* DeBugLinker */
#if MACINTOSH && MPW
/* #pragma unused(name) */
#endif /* MACINTOSH && MPW */
#endif /* DeBugLinker */
outop(op);
}
static novalue lemitl(op, lab, name)
int op, lab;
char *name;
{
#ifdef DeBugLinker
if (Dflag)
fprintf(dbgfile, "%ld:\t%d\tL%d\t\t\t# %s\n", (long)pc, op, lab, name);
#else /* DeBugLinker */
#if MACINTOSH && MPW
/* #pragma unused(name) */
#endif /* MACINTOSH && MPW */
#endif /* DeBugLinker */
if (lab >= maxlabels)
quit("out of label space");
outop(op);
if (labels[lab] <= 0) { /* forward reference */
outword(labels[lab]);
labels[lab] = WordSize - pc; /* add to front of reference chain */
}
else /* output relative offset */
outword(labels[lab] - (pc + WordSize));
}
static novalue lemitn(op, n, name)
int op;
word n;
char *name;
{
#ifdef DeBugLinker
if (Dflag)
fprintf(dbgfile, "%ld:\t%d\t%ld\t\t\t# %s\n", (long)pc, op, (long)n,
name);
#else /* DeBugLinker */
#if MACINTOSH && MPW
/* #pragma unused(name) */
#endif /* MACINTOSH && MPW */
#endif /* DeBugLinker */
outop(op);
outword(n);
}
static novalue lemitr(op, loc, name)
int op;
word loc;
char *name;
{
loc -= pc + ((IntBits/ByteBits) + WordSize);
#ifdef DeBugLinker
if (Dflag) {
if (loc >= 0)
fprintf(dbgfile, "%ld:\t%d\t*+%ld\t\t\t# %s\n",(long) pc, op,
(long)loc, name);
else
fprintf(dbgfile, "%ld:\t%d\t*-%ld\t\t\t# %s\n",(long) pc, op,
(long)-loc, name);
}
#else /* DeBugLinker */
#if MACINTOSH && MPW
/* #pragma unused(name) */
#endif /* MACINTOSH && MPW */
#endif /* DeBugLinker */
outop(op);
outword(loc);
}
static novalue lemitin(op, offset, n, name)
int op, n;
word offset;
char *name;
{
#ifdef DeBugLinker
if (Dflag)
fprintf(dbgfile, "%ld:\t%d\t%d,I+%ld\t\t\t# %s\n", (long)pc, op, n,
(long)offset, name);
#else /* DeBugLinker */
#if MACINTOSH && MPW
/* #pragma unused(name) */
#endif /* MACINTOSH && MPW */
#endif /* DeBugLinker */
outop(op);
outword(n);
outword(offset);
}
/*
* lemitint can have some pitfalls. outword is used to output the
* integer and this is picked up in the interpreter as the second
* word of a short integer. The integer value output must be
* the same size as what the interpreter expects. See op_int and op_intx
* in interp.s
*/
static novalue lemitint(op, i, name)
int op;
long i;
char *name;
{
#ifdef DeBugLinker
if (Dflag)
fprintf(dbgfile,"%ld:\t%d\t%ld\t\t\t# %s\n",(long)pc,op,(long)i,name);
#else /* DeBugLinker */
#if MACINTOSH && MPW
/* #pragma unused(name) */
#endif /* MACINTOSH && MPW */
#endif /* DeBugLinker */
outop(op);
outword(i);
}
static novalue lemiteven()
{
word x = 0;
register int len;
if (len = pc % (IntBits/ByteBits))
outblock((char *)x, (IntBits/ByteBits) - len);
}
static novalue lemitcon(k)
register int k;
{
register int i, j;
register char *s;
int csbuf[CsetSize];
union {
char ovly[1]; /* Array used to overlay l and f on a bytewise basis. */
long l;
double f;
} x;
if (lctable[k].c_flag & F_RealLit) {
#ifdef Double
/* access real values one word at a time */
{ int *rp, *rq;
rp = (int *) &(x.f);
rq = (int *) &(lctable[k].c_val.rval);
*rp++ = *rq++;
*rp = *rq;
}
#else /* Double */
x.f = lctable[k].c_val.rval;
#endif /* Double */
#ifdef DeBugLinker
if (Dflag) {
fprintf(dbgfile, "%ld:\t%d\n", (long)pc, T_Real);
dumpblock(x.ovly,sizeof(double));
fprintf(dbgfile, "\t\t\t( %g )\n",x.f);
}
#endif /* DeBugLinker */
outword(T_Real);
#ifdef Double
/* fill out real block with an empty word */
outword(0);
#endif /* Double */
outblock(x.ovly,sizeof(double));
}
else if (lctable[k].c_flag & F_CsetLit) {
for (i = 0; i < CsetSize; i++)
csbuf[i] = 0;
s = lctable[k].c_val.sval;
i = lctable[k].c_length;
while (i--) {
Setb(ToAscii(*s), csbuf);
s++;
}
j = 0;
for (i = 0; i < 256; i++) {
if (Testb(i, csbuf))
j++;
}
#ifdef DeBugLinker
if (Dflag) {
fprintf(dbgfile, "%ld:\t%d\n",(long) pc, T_Cset);
fprintf(dbgfile, "\t%d\n",j);
fprintf(dbgfile,(char *)csbuf,sizeof(csbuf));
}
#endif /* DeBugLinker */
outword(T_Cset);
outword(j); /* cset size */
outblock((char *)csbuf,sizeof(csbuf));
#ifdef DeBugLinker
if (Dflag)
dumpblock((char *)csbuf,CsetSize);
#endif /* DeBugLinker */
}
}
static novalue lemitproc(name, nargs, ndyn, nstat, fstat)
char *name;
int nargs, ndyn, nstat, fstat;
{
register int i;
register char *p;
int size;
/*
* FncBlockSize = sizeof(BasicFncBlock) +
* sizeof(descrip)*(# of args + # of dynamics + # of statics).
*/
size = (9*WordSize) + (2*WordSize) * (abs(nargs)+ndyn+nstat);
#ifdef DeBugLinker
if (Dflag) {
fprintf(dbgfile, "%ld:\t%d\n", (long)pc, T_Proc); /* type code */
fprintf(dbgfile, "\t%d\n", size); /* size of block */
fprintf(dbgfile, "\tZ+%ld\n",(long)(pc+size)); /* entry point */
fprintf(dbgfile, "\t%d\n", nargs); /* # arguments */
fprintf(dbgfile, "\t%d\n", ndyn); /* # dynamic locals */
fprintf(dbgfile, "\t%d\n", nstat); /* # static locals */
fprintf(dbgfile, "\t%d\n", fstat); /* first static */
fprintf(dbgfile, "\t%d\tI+%ld\t\t\t# %s\n", /* name of procedure */
(int)strlen(name), (long)(name-lsspace), name);
}
#endif /* DeBugLinker */
outword(T_Proc);
outword(size);
outword(pc + size - 2*WordSize); /* Have to allow for the two words
that we've already output. */
outword(nargs);
outword(ndyn);
outword(nstat);
outword(fstat);
outword(strlen(name));
outword(name - lsspace);
/*
* Output string descriptors for argument names by looping through
* all locals, and picking out those with F_Argument set.
*/
for (i = 0; i <= nlocal; i++) {
if (lltable[i].l_flag & F_Argument) {
p = lltable[i].l_name;
#ifdef DeBugLinker
if (Dflag)
fprintf(dbgfile, "\t%d\tI+%ld\t\t\t# %s\n", (int)strlen(p),
(long)(p-lsspace), p);
#endif /* DeBugLinker */
outword(strlen(p));
outword(p - lsspace);
}
}
/*
* Output string descriptors for local variable names.
*/
for (i = 0; i <= nlocal; i++) {
if (lltable[i].l_flag & F_Dynamic) {
p = lltable[i].l_name;
#ifdef DeBugLinker
if (Dflag)
fprintf(dbgfile, "\t%d\tI+%ld\t\t\t# %s\n", (int)strlen(p),
(long)(p-lsspace), p);
#endif /* DeBugLinker */
outword(strlen(p));
outword(p - lsspace);
}
}
/*
* Output string descriptors for local variable names.
*/
for (i = 0; i <= nlocal; i++) {
if (lltable[i].l_flag & F_Static) {
p = lltable[i].l_name;
#ifdef DeBugLinker
if (Dflag)
fprintf(dbgfile, "\t%d\tI+%ld\t\t\t# %s\n", (int)strlen(p),
(long)(p-lsspace), p);
#endif /* DeBugLinker */
outword(strlen(p));
outword(p - lsspace);
}
}
}
/*
* gentables - generate interpreter code for global, static,
* identifier, and record tables, and built-in procedure blocks.
*/
novalue gentables()
{
register int i;
register char *s;
register struct gentry *gp;
struct fentry *fp;
struct rentry *rp;
struct header hdr;
#if MVS
FILE *toutfile; /* temporary file for icode output */
#endif /* MVS */
lemiteven();
/*
* Output record constructor procedure blocks.
*/
hdr.records = pc;
#ifdef DeBugLinker
if (Dflag)
fprintf(dbgfile, "%ld:\t%d\t\t\t\t# record blocks\n",(long)pc, nrecords);
#endif /* DeBugLinker */
outword(nrecords);
for (gp = lgtable; gp < lgfree; gp++) {
if (gp->g_flag & (F_Record & ~F_Global)) {
s = gp->g_name;
gp->g_pc = pc;
#ifdef DeBugLinker
if (Dflag) {
fprintf(dbgfile, "%ld:\n", pc);
fprintf(dbgfile, "\t%d\n", T_Proc);
fprintf(dbgfile, "\t%d\n", RkBlkSize);
fprintf(dbgfile, "\t_mkrec\n");
fprintf(dbgfile, "\t%d\n", gp->g_nargs);
fprintf(dbgfile, "\t-2\n");
fprintf(dbgfile, "\t%d\n", gp->g_procid);
fprintf(dbgfile, "\t1\n");
fprintf(dbgfile, "\t%d\tI+%ld\t\t\t# %s\n", (int)strlen(s),
(long)(s-lsspace), s);
}
#endif /* DeBugLinker */
outword(T_Proc); /* type code */
outword(RkBlkSize); /* size of block */
outword(0); /* entry point (filled in by interp)*/
outword(gp->g_nargs); /* number of fields */
outword(-2); /* record constructor indicator */
outword(gp->g_procid); /* record id */
outword(1); /* serial number */
outword(strlen(s)); /* name of record */
outword(s - lsspace);
}
}
/*
* Output record/field table.
*/
hdr.ftab = pc;
#ifdef DeBugLinker
if (Dflag)
fprintf(dbgfile, "%ld:\t\t\t\t\t# record/field table\n", (long)pc);
#endif /* DeBugLinker */
for (fp = lftable; fp < lffree; fp++) {
#ifdef DeBugLinker
if (Dflag)
fprintf(dbgfile, "%ld:\n", (long)pc);
#endif /* DeBugLinker */
rp = fp->f_rlist;
for (i = 1; i <= nrecords; i++) {
if (rp != NULL && rp->r_recid == i) {
#ifdef DeBugLinker
if (Dflag)
fprintf(dbgfile, "\t%d\n", rp->r_fnum);
#endif /* DeBugLinker */
outword(rp->r_fnum);
rp = rp->r_link;
}
else {
#ifdef DeBugLinker
if (Dflag)
fprintf(dbgfile, "\t-1\n");
#endif /* DeBugLinker */
outword(-1);
}
#ifdef DeBugLinker
if (Dflag && (i == nrecords || (i & 03) == 0))
putc('\n', dbgfile);
#endif /* DeBugLinker */
}
}
/*
* Output descriptors for field names.
*/
hdr.fnames = pc;
for (fp = lftable; fp < lffree; fp++) {
s = fp->f_name;
#ifdef DeBugLinker
if (Dflag)
fprintf(dbgfile, "%ld:\t%d\tI+%ld\t\t\t# %s\n",
(long)pc, (int)strlen(s), (long)(s-lsspace), s);
#endif /* DeBugLinker */
outword(strlen(s)); /* name of field */
outword(s - lsspace);
}
/*
* Output global variable descriptors.
*/
hdr.globals = pc;
for (gp = lgtable; gp < lgfree; gp++) {
if (gp->g_flag & (F_Builtin & ~F_Global)) { /* function */
#ifdef DeBugLinker
if (Dflag)
fprintf(dbgfile, "%ld:\t%06lo\t%d\t\t\t# %s\n",
(long)pc, (long)D_Proc, -gp->g_procid, gp->g_name);
#endif /* DeBugLinker */
outword(D_Proc);
outword(-gp->g_procid);
}
else if (gp->g_flag & (F_Proc & ~F_Global)) { /* Icon procedure */
#ifdef DeBugLinker
if (Dflag)
fprintf(dbgfile, "%ld:\t%06lo\tZ+%ld\t\t\t# %s\n",
(long)pc,(long)D_Proc, (long)gp->g_pc, gp->g_name);
#endif /* DeBugLinker */
outword(D_Proc);
outword(gp->g_pc);
}
else if (gp->g_flag & (F_Record & ~F_Global)) { /* record constructor */
#ifdef DeBugLinker
if (Dflag)
fprintf(dbgfile, "%ld:\t%06lo\tZ+%ld\t\t\t# %s\n",
(long)pc, (long)D_Proc, (long)gp->g_pc, gp->g_name);
#endif /* DeBugLinker */
outword(D_Proc);
outword(gp->g_pc);
}
else { /* global variable */
#ifdef DeBugLinker
if (Dflag)
fprintf(dbgfile, "%ld:\t%06lo\t0\t\t\t# %s\n",(long)pc,
(long)D_Null, gp->g_name);
#endif /* DeBugLinker */
outword(D_Null);
outword(0);
}
}
/*
* Output descriptors for global variable names.
*/
hdr.gnames = pc;
for (gp = lgtable; gp < lgfree; gp++) {
#ifdef DeBugLinker
if (Dflag)
fprintf(dbgfile, "%ld:\t%d\tI+%ld\t\t\t# %s\n",
(long)pc, (int)strlen(gp->g_name), (long)(gp->g_name-lsspace),
gp->g_name);
#endif /* DeBugLinker */
outword(strlen(gp->g_name));
outword(gp->g_name - lsspace);
}
/*
* Output a null descriptor for each static variable.
*/
hdr.statics = pc;
for (i = lstatics; i > 0; i--) {
#ifdef DeBugLinker
if (Dflag)
fprintf(dbgfile, "%ld:\t0\t0\n", (long)pc);
#endif /* DeBugLinker */
outword(D_Null);
outword(0);
}
flushcode();
/*
* Output the string constant table and the two tables associating icode
* locations with source program locations. Note that the calls to write
* really do all the work.
*/
#ifdef DeBugLinker
if (Dflag) {
for (s = lsspace; s < lsfree; ) {
fprintf(dbgfile, "%ld:\t%03o\n", (long)pc, *s++);
for (i = 7; i > 0; i--) {
if (s >= lsfree)
break;
fprintf(dbgfile, " %03o\n", *s++);
}
putc('\n', dbgfile);
}
}
#endif /* DeBugLinker */
hdr.filenms = pc;
pc += (char *)fnmfree - (char *)fnmtbl;
hdr.linenums = pc;
pc += (char *)lnfree - (char *)lntable;
hdr.strcons = pc;
pc += lsfree - lsspace;
if (longwrite((char *)fnmtbl, (long)((char *)fnmfree - (char *)fnmtbl),
outfile) < 0)
quit("cannot write icode file");
if (longwrite((char *)lntable, (long)((char *)lnfree - (char *)lntable),
outfile) < 0)
quit("cannot write icode file");
if (longwrite(lsspace, (long)(lsfree - lsspace), outfile) < 0)
quit("cannot write icode file");
/*
* Output icode file header.
*/
hdr.hsize = pc;
strcpy((char *)hdr.config,IVersion);
hdr.trace = trace;
#ifdef DeBugLinker
if (Dflag) {
fprintf(dbgfile, "size: %ld\n", (long)hdr.hsize);
fprintf(dbgfile, "trace: %ld\n", (long)hdr.trace);
fprintf(dbgfile, "records: %ld\n", (long)hdr.records);
fprintf(dbgfile, "ftab: %ld\n", (long)hdr.ftab);
fprintf(dbgfile, "fnames: %ld\n", (long)hdr.fnames);
fprintf(dbgfile, "globals: %ld\n", (long)hdr.globals);
fprintf(dbgfile, "gnames: %ld\n", (long)hdr.gnames);
fprintf(dbgfile, "statics: %ld\n", (long)hdr.statics);
fprintf(dbgfile, "strcons: %ld\n", (long)hdr.strcons);
fprintf(dbgfile, "filenms: %ld\n", (long)hdr.filenms);
fprintf(dbgfile, "linenums: %ld\n", (long)hdr.linenums);
fprintf(dbgfile, "config: %s\n", hdr.config);
}
#endif /* DeBugLinker */
#ifdef Header
fseek(outfile, (long)MaxHeader, 0);
#else /* Header */
#if MVS
/*
* This kind of backpatching cannot work on a PDS member, and that's
* probably where the code is going. So the code goes out first to
* a temporary file, and then copied to the real icode file after
* the header is written.
*/
fseek(outfile, sizeof(hdr), SEEK_SET);
toutfile = outfile;
outfile = fopen(routname, "wb");
if (outfile == NULL)
quitf("cannot create %s",routname);
#else
fseek(outfile, 0L, 0);
#endif /* MVS */
#endif /* Header */
if (longwrite((char *)&hdr, (long)sizeof(hdr), outfile) < 0)
quit("cannot write icode file");
#if MVS
{
char *allelse = malloc(hdr.hsize);
if (hdr.hsize != fread(allelse, 1, hdr.hsize, toutfile) ||
longwrite(allelse, hdr.hsize, outfile) < 0)
quit("cannot write icode file");
free(allelse);
fclose(toutfile);
}
#endif /* MVS */
}
/*
* intout(i) outputs i as an int that is used by the runtime system
* IntBits/ByteBits bytes must be moved from &word[0] to &codep[0].
*/
static novalue intout(oint)
int oint;
{
int i;
union {
int i;
char c[IntBits/ByteBits];
} u;
CodeCheck(1);
u.i = oint;
for (i = 0; i < IntBits/ByteBits; i++)
codep[i] = u.c[i];
codep += IntBits/ByteBits;
pc += IntBits/ByteBits;
}
/*
* wordout(i) outputs i as a word that is used by the runtime system
* WordSize bytes must be moved from &oword[0] to &codep[0].
*/
static novalue wordout(oword)
word oword;
{
int i;
union {
word i;
char c[WordSize];
} u;
CodeCheck(1);
u.i = oword;
for (i = 0; i < WordSize; i++)
codep[i] = u.c[i];
codep += WordSize;
pc += WordSize;
}
/*
* outblock(a,i) output i bytes starting at address a.
*/
static novalue outblock(addr,count)
char *addr;
int count;
{
CodeCheck(count);
pc += count;
while (count--)
*codep++ = *addr++;
}
#ifdef DeBugLinker
/*
* dumpblock(a,i) dump contents of i bytes at address a, used only
* in conjunction with -L.
*/
static novalue dumpblock(addr, count)
char *addr;
int count;
{
int i;
for (i = 0; i < count; i++) {
if ((i & 7) == 0)
fprintf(dbgfile,"\n\t");
fprintf(dbgfile," %03o\n",(0377 & (unsigned)addr[i]));
}
putc('\n',dbgfile);
}
#endif /* DeBugLinker */
/*
* flushcode - write buffered code to the output file.
*/
static novalue flushcode()
{
if (codep > codeb)
if (longwrite(codeb, (long)codep - (long)codeb, outfile) < 0)
quit("cannot write icode file");
codep = codeb;
}
/*
* clearlab - clear label table to all zeroes.
*/
static novalue clearlab()
{
register int i;
for (i = 0; i < maxlabels; i++)
labels[i] = 0;
}
/*
* backpatch - fill in all forward references to lab.
*/
static novalue backpatch(lab)
int lab;
{
word p, r;
char *q;
char *cp, *cr;
register int j;
if (lab >= maxlabels)
quit("out of label space");
p = labels[lab];
if (p > 0)
quit("multiply defined label in ucode");
while (p < 0) { /* follow reference chain */
r = pc - (WordSize - p); /* compute relative offset */
q = codep - (pc + p); /* point to word with address */
cp = (char *) &p; /* address of integer p */
cr = (char *) &r; /* address of integer r */
for (j = 0; j < WordSize; j++) { /* move bytes from word pointed to */
*cp++ = *q; /* by q to p, and move bytes from */
*q++ = *cr++; /* r to word pointed to by q */
} /* moves integers at arbitrary addresses */
}
labels[lab] = pc;
}
#ifdef DeBugLinker
novalue idump(s) /* dump code region */
char *s;
{
int *c;
fprintf(stderr,"\ndump of code region %s:\n",s);
for (c = (int *)codeb; c < (int *)codep; c++)
fprintf(stderr,"%ld: %d\n",(long)c, (int)*c);
fflush(stderr);
}
#endif /* DeBugLinker */